package Q1;

import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Bank counter personnel pojo
 *
 * Teller 类中不多次启动线程
 * 修改方法：（使用 Lock，Condition）
 * 1）使用标记 isServe，表示该柜员是否提供服务，初始值为：isServe = false
 * 2）在构造函数中启动线程，循环等待标记 while (isServe == false)
 * 3）startServe 中设置标记 isServe = true，并唤醒等待线程
 * 4）stopServe 中设置标记 isServe = false
 */
@Data
public class Teller {

    /**
     * Counter initialize id
     */
    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    private static int gId = 1;

    /**
     * Counter id
     */
    private final int id = gId++;

    /**
     * Whether to start the service
     */
    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    private boolean isServe = false;

    /**
     * Service thread lock
     */
    @Getter(AccessLevel.NONE)
    private final Lock lock = new ReentrantLock();

    /**
     * Service thread condition (or queue)
     */
    @Getter(AccessLevel.NONE)
    private final Condition condition = lock.newCondition();

    /**
     * A service listener for passing messages
     */
    private TellerListener listener;

    /**
     * Teller constructor. Used to initialize and start the
     * service thread.
     *
     * @param queue consumer queue
     */
    @SuppressWarnings("all")
    public Teller(BlockingQueue<Customer> queue) {
        new Thread(() -> {
            // 通过 while-true 避免线程结束
            while (true) {
                // 获取锁
                lock.lock();

                // 当服务没有开启时，阻塞线程
                while (!isServe) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 释放锁
                lock.unlock();

                // 进行服务
                try {
                    // 标识当前窗口空闲
                    if (listener != null) {
                        listener.onServe(null);
                    }

                    // 有顾客，进行服务
                    final Customer customer = queue.take();
                    if (listener != null) {
                        listener.onServe(customer);
                    }

                    // 随机暂停 5-10 秒，表示服务时间
                    int t = (int) (Math.random() * 5000 + 5000);
                    System.out.printf("> [%d] 号柜员为 [%d] 号顾客服务，服务时间 [%d] 秒\n", id, customer.getId(), t);
                    Thread.sleep(t);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * Start service, fetching customer service from the wait queue
     */
    public void startServe() {
        System.out.printf("$ [%d] 号柜员开始服务\n", id);

        // 获取锁
        lock.lock();
        // 标识开启服务
        isServe = true;
        // 唤醒服务线程
        condition.signal();
        // 释放锁
        lock.unlock();
    }

    /**
     * Stop service
     */
    public void stopServe() {
        System.out.printf("$ [%d] 号柜员停止服务\n", id);

        // 关闭服务
        isServe = false;
    }

}
